use reqwest::Client;
use serde::{Deserialize, Serialize};
use std::{
    ffi::CString,
    net::TcpStream,
    path::PathBuf,
    sync::{Arc, RwLock},
    time::Duration,
};
use tokio::sync::RwLock as TokioRwLock;
use tokio_cron_scheduler::{job, Job, JobScheduler};
use tracing::info;


use crate::{
    config::ApplicationConfig, controller::{admin::router as admin_router, manager::router}, cryptmd5, lock::dog::{SoftdogManager, SoftdogResult}, serve::AppBuilder, Ext, TypeJobScheduler, APPLICATION_CONTEXT, update_main_thread_status
};
use async_channel::{Receiver, Sender};
use dashmap::DashMap;
use once_cell::sync::OnceCell;
use serde_json::{json, Value};
use tauri::{
    path::BaseDirectory,
    plugin::{Builder, TauriPlugin},
    AppHandle, Emitter, Listener, Manager, Runtime,
};
const GK: &str = "xilidata.lock";

#[derive(Debug, Serialize, Deserialize)]
struct TokenResponse {
    access_token: String,
    expires_in: i64,
}
/// 管理锁
/// 主要管理本地锁的初始化，以及锁的绑定，解绑，续期，新购，退订
pub struct ManagerLock {
    client: OnceCell<Client>,
    map: DashMap<u32, Value>,
    softdog: OnceCell<SoftdogManager>,
    pub sender: Sender<(String, Value)>,
    token: RwLock<Option<String>>,
}
impl ManagerLock {
    /// 获取token
    pub fn get_token(&self) -> Option<String> {
        update_main_thread_status();
        let token = self.token.read().unwrap();
        token.clone()
    }

    /// 初始化锁
    pub fn init(&self, newsns: Vec<u32>) {
        update_main_thread_status();
        // 获取map 所有的key
        let keys: Vec<u32> = self.map.iter().map(|v| v.key().clone()).collect();
        if newsns.len() > 0 {
            let mut sns = Vec::new();
            let mut error_sns = Vec::new();
            for sn in newsns.clone() {
                if !keys.contains(&sn) {
                    info!("初始化新锁: {}", sn);
                    let res = self.check(sn);

                    if res.is_ok() {
                        sns.push(sn);
                    } else {
                        error_sns.push(sn);
                        info!("初始化锁信息失败: {:?}", res.err().unwrap());
                    }
                }
            }
            if sns.len() > 0 {
                let _ = self
                    .sender
                    .send_blocking(("new_lock".to_string(), json!(sns)));
                sns.clear();
            }
            // 找出 keys 在 newsns 中不存在的key
            for key in keys {
                if !newsns.contains(&key) {
                    self.map.remove(&key);
                    if !error_sns.contains(&key) {
                        sns.push(key);
                    }
                }
            }
            if sns.len() > 0 {
                let _ = self
                    .sender
                    .send_blocking(("delete_lock".to_string(), json!(sns)));
            }
        } else {
            self.map.clear();
        }
    }
    /// 初始化锁
    pub fn new(resource_path: PathBuf, sender: Sender<(String, Value)>) -> Self {
        let client = Client::builder()
        .pool_idle_timeout(Duration::from_secs(30))
        .build()
        .unwrap();
        Self {
            client: OnceCell::with_value(client),
            map: DashMap::new(),
            softdog: OnceCell::with_value(SoftdogManager::new(resource_path)),
            sender: sender,
            token: RwLock::new(None),
        }
    }
    /// 获取锁
    pub fn get_sns(&self) -> Result<Vec<u32>, Box<dyn std::error::Error>> {
        let dog = self.softdog.get().unwrap();
        let sns = dog.get_sn();
        Ok(sns)
    }
    /// 获取主锁
    pub fn has_mainlock(&self) -> u32 {
        let dog = self.softdog.get().unwrap();
        let sns = dog.get_sn();
        for sn in sns {
            let res = dog.set_limit(sn, "12345678");
            if res.status == 200 && res.data == Some("1".to_string()) {
                return sn;
            }
        }
        0
    }
    /// 设置锁信息
    pub fn set_info(&self, sn: u32, info: Value) {
        self.map
            .insert(sn, json!({"init": true,"serial":sn,"info":info}));
    }
    /// 获取锁信息
    pub fn get_info(&self, sn: u32) -> Option<Value> {
        self.map.get(&sn).map(|v| v.clone())
    }
    pub fn get_info_all(&self) -> Vec<Value> {
        self.map.iter().map(|v| v.value().clone()).collect()
    }
    /// 写锁
    pub fn write_info(
        &self,
        command: Value,
        info: Value,
    ) -> Result<(), Box<dyn std::error::Error>> {
        let mut info = info;
        let serial = command["serial"].as_u64().unwrap() as u32;
        let password = command["dynamicPassword"].as_str().unwrap();
        let command = command["command"].as_u64().unwrap();
        if command == 99 {
            let result = self.write(1, serial, password, cryptmd5(GK).to_string());
            if result.status == 200 {
                info = json!({"main":null,"resource":[]})
            } else {
                return Err(Box::new(std::io::Error::new(
                    std::io::ErrorKind::Other,
                    result.msg.clone().unwrap(),
                )));
            }
        }
        let info = info.to_string();
        let result = self.write(2, serial, password, cryptmd5(&info).to_string());
        if result.status != 200 {
            return Err(Box::new(std::io::Error::new(
                std::io::ErrorKind::Other,
                result.msg.clone().unwrap(),
            )));
        }
        let result = self.write(3, serial, "12345678", info);
        if result.status != 200 {
            return Err(Box::new(std::io::Error::new(
                std::io::ErrorKind::Other,
                result.msg.clone().unwrap(),
            )));
        }
        Ok(())
    }
    /// 写锁

    fn write(&self, mode: u32, serial: u32, password: &str, json: String) -> SoftdogResult {
        let dog = self.softdog.get().unwrap();
        let keys: Vec<u32> = self.map.iter().map(|v| v.key().clone()).collect();
        if !keys.contains(&serial) {
            dog.module_set(serial);
        }
        let mut password = password.to_string();
        let magager = self.softdog.get().unwrap();
        let addr = match mode.cmp(&2) {
            std::cmp::Ordering::Less => {
                password = "abcdefgh".to_string();
                1
            }
            std::cmp::Ordering::Equal => {
                2001
            },
            std::cmp::Ordering::Greater => {
                40001},
        };
        let result = magager.write(json, serial, addr, CString::new(password).unwrap());
        result
    }
    /// 获取激活密码
    pub fn get_active_psd(
        &self,
        password: &str,
        main_serial: u32,
        target_serial: u32,
        ul_limit: u32,
    ) -> SoftdogResult {
        let dog = self.softdog.get().unwrap();
        let psd = dog.get_active_psd(password, main_serial, 0, 0, target_serial, ul_limit);
        info!("获取激活密码:{}", psd.msg.clone().unwrap());
        psd
    }
    /// 读锁
    fn read(&self, mode: u32, serial: u32, password: &str) -> SoftdogResult {
        let mut password = password.to_string();
        let magager = self.softdog.get().unwrap();
        let addr = match mode.cmp(&2) {
            std::cmp::Ordering::Less => {
                password = "abcdefgh".to_string();
                1
            }
            std::cmp::Ordering::Equal => {
                password = "abcdefgh".to_string();
                2001
            },
            std::cmp::Ordering::Greater => {
                password = "abcdefgh".to_string();
                40001
            },
        };
        let data = magager.read(serial, addr, CString::new(password).unwrap());
        data
    }
    /// 检查锁
    pub fn check(&self, serial: u32) -> Result<(), Box<dyn std::error::Error>> {
        let dog: &SoftdogManager = self.softdog.get().unwrap();
        let res = dog.module_set(serial);
        if res.status != 200 {
            return Err(Box::new(std::io::Error::new(
                std::io::ErrorKind::Other,
                res.msg.unwrap(),
            )));
        }
        let SoftdogResult { status, msg, data } = self.read(1, serial, "12345678");
        match (status, data) {
            (200, Some(data)) => {
                if cryptmd5(GK) != data {
                    return Err(Box::new(std::io::Error::new(
                        std::io::ErrorKind::Other,
                        "盗版锁".to_string(),
                    )));
                }
            }
            _ => {
                return Err(Box::new(std::io::Error::new(
                    std::io::ErrorKind::Other,
                    msg.unwrap(),
                )));
            }
        }
        let SoftdogResult { status, msg, data } = self.read(2, serial, "12345678");
        let v2 = match (status, data) {
            (200, Some(data)) => data,
            _ => {
                return Err(Box::new(std::io::Error::new(
                    std::io::ErrorKind::Other,
                    msg.unwrap(),
                )));
            }
        };
        let SoftdogResult { status, msg, data } = self.read(3, serial, "12345678");
        let v3 = match (status, data) {
            (200, Some(data)) => data,
            _ => {
                return Err(Box::new(std::io::Error::new(
                    std::io::ErrorKind::Other,
                    msg.unwrap(),
                )));
            }
        };
        if cryptmd5(&v3) != v2 {
            info!("盗版锁: {}", serial);
            return Err(Box::new(std::io::Error::new(
                std::io::ErrorKind::Other,
                "盗版锁".to_string(),
            )));
        }
        let v4 = serde_json::from_str::<Value>(&v3).unwrap();
        info!("初始化锁信息: {:?}", v4);
        self.set_info(serial, v4);
        info!("初始化成功: {}", serial);
        Ok(())
    }
    pub fn check_network(&self) -> bool {
        TcpStream::connect("www.baidu.com:80").is_ok()
    }
    /// 认证登录
    pub async fn auth_login(&self) -> Result<(), Box<dyn std::error::Error>> {
        let config = APPLICATION_CONTEXT.get::<ApplicationConfig>();
        let url = format!("{}/api/auth-resource/oauth/token", config.base_url());

        let response = self.client.wait()
            .post(&url)
            .form(&[
                ("grant_type", "client_credentials"),
                ("client_id", "SUPER_ADMIN"),
                ("client_secret", "xjlidong123"),
            ])
            .send()
            .await?;

        if response.status().is_success() {
            let token_data: TokenResponse = response.json().await?;
            let mut token = self.token.write().unwrap();
            *token = Some(token_data.access_token);
        }

        Ok(())
    }
    /// 执行命令
    pub async fn execute_cammand(&self) -> Result<(), Box<dyn std::error::Error>> {
        update_main_thread_status();
        let token = self.get_token();
        if token.is_none() {
            self.auth_login().await?;
            return Ok(());
        }
        let token = token.unwrap();
        // Only proceed if there are devices
        let keys: Vec<u32> = self.get_sns().unwrap();
        if keys.is_empty() {
            return Ok(());
        }

        let client = self.client.wait();
        let config = APPLICATION_CONTEXT.get::<ApplicationConfig>();
        let url = format!(
            "{}/api/hardware-resources/1/hardware/hardwarepool/pollcommand",
            config.base_url()
        );

        let response = client
            .post(&url)
            .header("Content-Type", "application/json")
            .header("Authorization", format!("Bearer {}", token))
            .header("Product_code", "AGENCY_ADMIN")
            .json(&keys)
            .send()
            .await?;

        if response.status().is_success() {
            let data: Value = response.json().await?;
            if let Some(result) = data.get("result").and_then(|r| r.as_array()) {
                // Sort results by recDate in ascending order
                let mut sorted_results = result.clone();
                info!("结果：{}",sorted_results.len());
                sorted_results.sort_by(|a, b| {
                    let date_a = a.get("recDate").and_then(|d| d.as_str()).unwrap_or("");
                    let date_b = b.get("recDate").and_then(|d| d.as_str()).unwrap_or("");
                    date_a.cmp(date_b)
                });
                // Process each result
                for result in sorted_results {
                    // TODO: Implement command execution logic
                    // This would be equivalent to self.onExecuteCammand(result[i]) in JS
                    let _ = self.on_execute_cammand(result.clone()).await;
                }
            }
        }
        Ok(())
    }
    /// 执行命令
    pub async fn on_execute_cammand(&self, row: Value) -> Result<(), Box<dyn std::error::Error>> {
        update_main_thread_status();
        let serial = row["serial"].as_u64().unwrap() as u32;
        let command = row["command"].as_u64().unwrap();
        let description = row["description"].as_str().unwrap_or_default();
        let sequence_nbr = row["sequenceNbr"].as_str().unwrap();

        let mut params: Option<Value> = None;

        match command {
            99 => {
                params = Some(json!(GK));
            }
            5 => {
                // 绑定主体
                let mut data: Value = self
                    .get_info(serial)
                    .unwrap_or(json!({"info":{"main":null,"resource":[]}}))["info"]
                    .clone();
                info!("绑定主体1: {:?}", &data);
                let main_data = serde_json::from_str::<Value>(description)?;
                data.as_object_mut()
                    .unwrap()
                    .insert("main".to_string(), main_data);
                info!("绑定主体: {:?}", &data);
                params = Some(data);
            }
            1 => {
                // 解绑主体
                params = Some(json!({"main":null,"resource":[]}));
            }
            3 => {
                // 报告丢失
                let mut data = self.get_info(serial).unwrap()["info"].clone();
                data.as_object_mut()
                    .unwrap()
                    .insert("loss".to_string(), json!(2));
                params = Some(data);
            }
            7 => {
                // 取消报告丢失
                let mut data = self.get_info(serial).unwrap()["info"].clone();
                data.as_object_mut().unwrap().remove("loss");
                params = Some(data);
            }
            2 => {
                // 续期
                let mut data = self.get_info(serial).unwrap()["info"].clone();
                let command_data = serde_json::from_str::<Value>(description)?;
                if let Some(resources) = data["resource"].as_array_mut() {
                    for resource in resources {
                        if resource["id"] == command_data["id"] {
                            resource["end_time"] = command_data["end_time"].clone();
                            break;
                        }
                    }
                }
                params = Some(data);
            }
            6 => {
                // 新购
                let mut data: Value = self.get_info(serial).unwrap()["info"].clone();
                let command_data = serde_json::from_str::<Value>(description)?;
                if let Some(resources) = data["resource"].as_array_mut() {
                    resources.push(command_data);
                } else {
                    data.as_object_mut()
                        .unwrap()
                        .insert("resource".to_string(), json!([command_data]));
                }
                info!("新购: {:?}", &data);
                params = Some(data);
            }
            8 => {
                // 取消新购
                let mut data = self.get_info(serial).unwrap()["info"].clone();
                let command_data = serde_json::from_str::<Value>(description)?;
                if let Some(resources) = data["resource"].as_array_mut() {
                    resources.retain(|item| item["id"] != command_data["id"]);
                }
                params = Some(data);
            }
            _ => {
                info!("不支持的命令: {}", command);
            }
        }

        if let Some(params) = params {
            info!("执行命令: {:?}", params);
            let mut receipt_params = json!({
                "sequenceNbr": sequence_nbr,
                "status": 1,
                "errorMsg": ""
            });

            match self.write_info(row.clone(), params.clone()) {
                Ok(_) => {
                    if command != 99 {
                        self.set_info(serial, params);
                    }
                }
                Err(e) => {
                    receipt_params["status"] = json!(2);
                    receipt_params["errorMsg"] = json!(e.to_string());
                    let _ = self
                        .sender
                        .send_blocking(("lock_error".to_string(), json!(e.to_string())));
                }
            }

            // 发送回执到服务器
            let client = self.client.wait();
            let config = APPLICATION_CONTEXT.get::<ApplicationConfig>();
            let url = format!(
                "{}/api/hardware-resources/1/hardware/hardwarepool/commandupdate",
                config.base_url()
            );
            let token = self.get_token().unwrap();

            let _ = client
                .post(&url)
                .header("Content-Type", "application/json")
                .header("Authorization", format!("Bearer {}", token))
                .header("Product_code", "AGENCY_ADMIN")
                .json(&receipt_params)
                .send()
                .await?;
        }

        Ok(())
    }
}
async fn start<R: Runtime>(app: &AppHandle<R>) {
    let sched = APPLICATION_CONTEXT.get::<TypeJobScheduler>();
    let app_clone = app.clone();
    let job = Job::new_async("1/5 * * * * *", move |_uuid, _l| {
        let app1 = app_clone.clone();
        Box::pin(async move {
            let manager = app1.manager();
            let alive = manager.check_network();
            let _ = app1.emit("netlinstener", alive);
            let sns = manager.get_sns().unwrap();
            info!("获取锁号列表: {:?}", sns);
            manager.init(sns.clone());
            let _ = app1.emit("timerJobProgress", sns);
        })
    });
    sched.read().await.add(job.unwrap()).await.unwrap();
}

async fn poll_add_execute_cammand<R: Runtime>(app: &AppHandle<R>) {
    let sched = APPLICATION_CONTEXT.get::<TypeJobScheduler>();
    let app_clone = app.clone();
    let job = Job::new_async("1/3 * * * * *", move |_uuid, _l| {
        let app1 = app_clone.clone();
        Box::pin(async move {
            let manager = app1.manager();
            let _ = manager.execute_cammand().await;

        })
    });
    sched.read().await.add(job.unwrap()).await.unwrap();
}

async fn serve(manager_lock_ref: Arc<ManagerLock>) {
    let app = router().with_state(manager_lock_ref.clone());
    let app_admin = admin_router().with_state(manager_lock_ref.clone());
    AppBuilder::new()
        .next("/controller/manager", app.clone())
        .next("/controller/admin", app_admin.clone())
        .next("/manager", app.clone())
        .next("/admin", app_admin.clone())
        .build()
        .run()
        .await;
}
async fn handle_message<R: Runtime>(app: AppHandle<R>, receiver: Receiver<(String, Value)>) {
    while let Ok((command, info)) = receiver.recv().await {
        let app_clone = app.clone();
        info!("发送消息: {:?}", &command);
        let _ = app_clone.emit(&command, info);
    }
}
pub fn init_manager_lock<R: Runtime>(app: &AppHandle<R>) -> crate::Result<Arc<ManagerLock>> {
    let resource_path = if cfg!(debug_assertions) {
        app.app_handle()
            .path()
            .resolve("./cdll9.dll", BaseDirectory::Resource)
            .unwrap()
    } else {
        app.app_handle()
            .path()
            .resolve("./cdll9.dll", BaseDirectory::Resource)
            .unwrap()
    };

    let (sender, receiver) = async_channel::unbounded();

    let manager_lock = Arc::new(ManagerLock::new(resource_path, sender));

    let manager_lock_ref = manager_lock.clone();
    tokio::task::spawn(async move {
        serve(manager_lock_ref).await;
    });
    let app2 = app.clone();
    tokio::task::spawn(async move {
        handle_message(app2, receiver).await;
    });

    Ok(manager_lock)
}

/// Initializes the plugin.
pub fn init<R: Runtime>() -> TauriPlugin<R> {
    Builder::new("manager_lock")
        .setup(|app, _api: tauri::plugin::PluginApi<R, ()>| {
            #[cfg(desktop)]
            {
                let manager_lock = init_manager_lock(&app).unwrap();
                app.manage(manager_lock);
                let app_clone = app.clone();
                let app3 = app.clone();
                tokio::task::spawn(async move {
                    start(&app_clone).await;
                    poll_add_execute_cammand(&app3).await;
                    let sched = APPLICATION_CONTEXT.get::<TypeJobScheduler>();
                    sched.read().await.start().await.unwrap();
                });
            }
            Ok(())
        })
        .build()
}
